package com.example.take_out_admin.generator;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.sql.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Properties;
import java.util.Scanner;

/**
 * @author: wuyunbin
 * @create: 2023-04-03 18:41
 * @Description: 代码生成器
 */
public class AnitaGenerator {
    /**
     * 数据库用户名
     */
    private static String DB_USER_NAME = "root";
    /**
     * 数据库密码
     */
    private static String DB_PASSWORD = "123456";
    /**
     * 数据库地址
     */
    private static String BASE_URL = "jdbc:mysql://localhost:3306/";
    /**
     * 数据库名
     */
    private static String DB_NAME = "";

    /**
     * 数据库端口及配置
     */
    private static final String INFO = "?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC";

    private static String AUTHOR = "";

    /**
     * 1. 父模块包名
     * 2. 输出目录
     * 如果还有父模块则要在src前加上父模块包名，注意：不包含项目包名
     * 如PARENT_MODULE = demo-service/demo-user
     * PROJECT_PATH = /src/main/java
     */
    private static String PARENT_MODULE = "";
    private static final String PROJECT_PATH = "/src/main/java";
    /**
     * Group包名，/src/main/java后面的路径名
     */
    private static String GROUP_PATH = "";
    /**
     * 1. 过滤表前缀, 如果要过滤多个, 则需要到方法中添加, 以逗号为分隔
     * 2. 过滤表后缀 比较少用, 要用的话自己去方法的括号里面加....
     * 3. 过滤字段前缀 比较少用, 要用的话自己去方法的括号里面加....
     * 4. 过滤字段后缀 比较少用, 要用的话自己去方法的括号里面加....
     */
    private static String TABLE_PREFIX = "";

    /**
     * ！！！开始启动 ！！！
     */
    public static void main(String[] args) {

        String isDefault = scanner("使用默认配置连接数据库？1-是 2-否");

        if (!"1".equals(isDefault)) {
            DB_USER_NAME = scanner("用户名");
            DB_PASSWORD = scanner("密码");
        }

        //显示本机数据库
        ArrayList<String> databases = getDatabases();
        for (int i = 0; i < databases.size(); i++) {
            System.out.println(i + "\t" + databases.get(i));
        }

        DB_NAME = databases.get(Integer.parseInt(scanner("请选择数据库")));
        System.out.println("* 如果还有父模块则要在src前加上父模块包名，注意：不包含项目包名");
        System.out.println("* /demo-service/demo-user !!注意前面的 / !!");

        String path = AnitaGenerator.class.getResource("/").getPath().replace("target/classes/", "");
        System.out.println(path);
        String[] split = path.split("/");
        ArrayList<String> modules = new ArrayList<>();
        String name = split[0];
        for (int i = split.length - 1; i >= 0; i--) {
            name = split[i] + "/" + name;
            modules.add("/" + name);
        }

        System.out.println("推算可以使用的模块名有：");
        for (int i = 0; i < modules.size(); i++) {
            System.out.println(i + " " + modules.get(i));
        }

        String choiceModule = scanner("选择模块，选择-1表示不选择任何一个，自己输入");

        if ("-1".equals(choiceModule)) {
            PARENT_MODULE = scanner("输入模块名");
        } else {
            PARENT_MODULE = modules.get(Integer.parseInt(choiceModule));
        }

        GROUP_PATH = scanner("包名 举个例子：com.wuyunbin.antita");
        AUTHOR = scanner("作者");

        TABLE_PREFIX = scanner("前缀");
        // 数据库连接url
        String dbUrl = BASE_URL + DB_NAME + INFO;
        FastAutoGenerator.create(dbUrl, DB_USER_NAME, DB_PASSWORD)
                // 全局配置
                .globalConfig(builder -> builder
                        // 禁止打开输出目录
                        .disableOpenDir()
                        // 设置输出目录
                        .outputDir(System.getProperty("user.dir") + PARENT_MODULE + PROJECT_PATH)
                        // 设置作者信息
                        .author(AUTHOR)
                        // 开启 swagger 模式
                        .enableSwagger()
                        // 实体类中时间策略
                        .dateType(DateType.ONLY_DATE)
                        // 生成日期
                        .commentDate("yyyy-MM-dd")
                )

                // 包配置
                .packageConfig(builder -> builder
                        // 父包名
                        .parent(GROUP_PATH)
                        // 父包模块名 注释即为无
                        .moduleName("")
                        // Entity 包名
                        .entity("entity")
                        // Service 包名
                        .service("service")
                        // Service Impl 包名
                        .serviceImpl("service.impl")
                        // Mapper 包名 dao层
                        .mapper("mapper")
                        // Mapper XML 包名
                        .xml("mapper")
                        // Controller 包名
                        .controller("controller")
                        // other(String)
                        //.other("utils")
                        // 将Mapper xml生成到resources目录下
                        .pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + PARENT_MODULE + "/src/main/resources/mappers"))
                )

                // 策略配置
                .strategyConfig((scanner, builder) -> {
                    builder.addInclude()
                            // 开启大写命名
                            // .enableCapitalMode()
                            // 开启跳过视图
                            // .enableSkipView()
                            // 增加过滤表前缀
                            .addTablePrefix(TABLE_PREFIX)
                            // 增加过滤表后缀
                            .addTableSuffix("")
                            // 增加过滤字段前缀
                            .addFieldPrefix("")
                            // 增加过滤字段后缀
                            .addFieldSuffix("")

                            // 实体策略配置
                            .entityBuilder()
                            // 禁用生成 serialVersionUID
                            //.disableSerialVersionUID()
                            // 开启链式模型
                            // .enableChainModel()
                            // 开启 lombok 模型
                            .enableLombok()
                            // 开启生成实体时生成字段注解
                            .enableTableFieldAnnotation()
                            // 乐观锁字段名(数据库)
                            .versionColumnName("version")
                            // 乐观锁属性名(实体)
                            .versionPropertyName("version")
                            // 逻辑删除字段名(数据库)
                            .logicDeleteColumnName("deleted")
                            // 逻辑删除属性名(实体)
                            .logicDeletePropertyName("deleted")
                            // 数据库表映射到实体的命名策略 -- 下划线转驼峰命名
                            .naming(NamingStrategy.underline_to_camel)
                            // 数据库表字段映射到实体的命名策略 -- 下划线转驼峰命名
                            .columnNaming(NamingStrategy.underline_to_camel)

                            // 阿里巴巴开发规范之创建时间、更新时间 交由mybatis-plus处理，如若交给数据库处理，则取消此设置
                            // .addTableFills(new Column("create_time", FieldFill.INSERT), new Column("update_time", FieldFill.INSERT_UPDATE))
                            // mapper 策略配置
                            .mapperBuilder()
                            // 设置父类
                            .superClass(BaseMapper.class)
                            // 格式化 mapper 文件名称
                            .formatMapperFileName("%sMapper")
                            // 格式化 xml 实现类文件名称
                            .formatXmlFileName("%sMapper")
                            // 开启 @Mapper 注解
                            .enableMapperAnnotation()
                            // 生成通用的resultMap
                            .enableBaseResultMap()

                            // service 策略配置
                            .serviceBuilder()
                            // 格式化 service 接口文件名称
                            .formatServiceFileName("%sService")
                            // 格式化 service 实现类文件名称
                            .formatServiceImplFileName("%sServiceImpl")

                            // controller 策略配置
                            .controllerBuilder()
                            // 格式化文件名称
                            .formatFileName("%sController")
                            // 开启生成@RestController 控制器
                            .enableRestStyle();
                })
                // 以下为解决实体类data注解，若不需要则可以注释
                // ------------------开始-------------------
                .templateConfig(builder -> {
                    // 实体类使用我们自定义模板 -- 模板位置
                    builder.entity("templates/myEntity.java");
                })
                .templateEngine(new FreemarkerTemplateEngine())
                // ------------------结束-------------------
                // 开始处理
                .execute();
        System.out.println("生成完成");
    }

    /**
     * 读取控制台内容信息
     */
    private static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        System.out.println(("请输入" + tip + "："));
        if (scanner.hasNext()) {
            String next = scanner.next();
            if (!"".equals(next)) {
                return next;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "！");
    }

    private static ArrayList<String> getDatabases() {
        ArrayList<String> databases = new ArrayList<>();

        Properties props = new Properties();
        props.setProperty("user", DB_USER_NAME);
        props.setProperty("password", DB_PASSWORD);
        props.put("remarksReporting", "true");
        //不加这个一行会读不到备注内容
        props.setProperty("useInformationSchema", "true");

        String url = "jdbc:mysql://127.0.0.1:3306/?characterEncoding=UTF8&nullCatalogMeansCurrent=true&useSSL=false";

        try {
            Connection connection = DriverManager.getConnection(url, props);

            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet catalogs = metaData.getCatalogs();

            while (catalogs.next()) {
                String catalog = catalogs.getString("TABLE_CAT");
                databases.add(catalog);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        return databases;
    }
}